package org.xx.sipahi;

import org.apache.commons.vfs2.FileContent;
import org.apache.commons.vfs2.FileName;
import org.apache.commons.vfs2.FileObject;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import static org.apache.commons.io.IOUtils.copyLarge;
import static org.xx.armory.commons.Validators.rejectIfNull;

/**
 * 文件内容引用。
 */
public final class FileContentRef
        implements Closeable {
    private final String path;
    private final boolean readable;
    private final boolean writable;
    private final FileContent fileContent;

    /**
     * 构造文件内容引用。
     *
     * @param rootFileName
     *         根文件对象的名字。
     * @param fileObject
     *         文件对象。
     * @throws IllegalArgumentException
     *         如果参数{@code fileObject}是{@code null}。如果参数{@code path}是{@code null}或者只包含空白字符，或者不是以斜线开头。
     * @throws IOException
     *         如果根据文件对象获取文件内容出错。
     */
    public FileContentRef(
            FileName rootFileName,
            FileObject fileObject
    )
            throws IOException {
        rejectIfNull(rootFileName, "rootFileName");
        rejectIfNull(fileObject, "fileObject");

        this.path = fileObject.getName().getPath().substring(rootFileName.getPath().length());
        this.readable = fileObject.isReadable();
        this.writable = fileObject.isWriteable();
        this.fileContent = fileObject.getContent();
    }

    /**
     * 获取文件长度。
     *
     * @return 文件长度。
     */
    public final long getSize()
            throws IOException {
        return this.fileContent.getSize();
    }

    /**
     * 获取最后修改日期。
     *
     * @return 最后修改日期。
     */
    public final long getLastModified()
            throws IOException {
        return this.fileContent.getLastModifiedTime();
    }

    public final boolean isReadable() {
        return this.readable;
    }

    public final boolean isWritable() {
        return this.writable;
    }

    /**
     * 将文件内容写入到输出流。
     *
     * @param out
     *         输出流。
     * @throws IllegalArgumentException
     *         如果参数{@code out}是{@code null}。
     * @throws java.io.IOException
     *         如果写入文件内容时出现错误。
     */
    public final void write(
            OutputStream out
    )
            throws IOException {
        try (final var stream = this.fileContent.getInputStream()) {
            copyLarge(stream, out);

            out.flush();
        }
    }

    /**
     * 从输入流读取文件内容。
     *
     * @param in
     *         输入流。
     * @throws IllegalArgumentException
     *         如果参数{@code in}是{@code null}。
     * @throws java.io.IOException
     *         如果读取文件内容到时出现错误。
     */
    public final void read(
            InputStream in
    )
            throws IOException {
        try (final var stream = this.fileContent.getOutputStream()) {
            copyLarge(in, stream);

            stream.flush();
        }
    }

    /**
     * 获取路径，一定以斜线开头。
     *
     * @return 文件名。
     */
    public final String getPath() {
        return this.path;
    }

    @Override
    public void close()
            throws IOException {
        this.fileContent.close();
    }
}
